-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Fix the interpreted version of Expression<>.Compile() for setting field on value types #116901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fix the interpreted version of Expression<>.Compile() for setting field on value types #116901
Conversation
@333fred @cston you are both listed as owners of System.Linq.Expressions so just trying to make sure this hits your radar. Obviously due to this there isn't too much life in this area, but this is a bug fix to an issue that I have had at work. But this PR, alongside this issue - which I note was apparently fixed, but not merged - are proving that the interpreted "compile" operation is somewhat flakey in it's current incarnation. So to be it should either be marked as obsolete, or there bugs fixes should make it into the mainline. Anyways, the errors that I'm seeing that are generated in the build here are not caused by this PR - I have run the test suite on both Windows and Linux (Ubuntu) and they all pass - so I'm not sure if I can do anything more other than continue to merge in mainline changes... |
Mono and NativeAOT legs have failing System.Linq.Expressions.Tests tests related to this PR:
|
Yes, the System.Linq.Expression interpreter has limitations that cause it to produce different results. The one you are trying to fix has to do with not being able to represent byrefs with full fidelity. #19286 is an example of observable behavior difference caused by the same limitation. |
Hi @jkotas, thanks for taking the time to have a bit of a look. That example is a bit different, although the above issue possibly could be resolved in the similar way (although I'm not sure). This is not for shared references, this is purely to denote the case for when you have a value type field inside another object and you need to set it's value. struct Inner { public int Value; }
class Outer { public Inner Inner; }
...
outer.Inner.Value = 42; // this currently fails to set the correct version due to the boxed version added So the PR added a delayed object to the stack which is the root along with field accessors. This can (and is in most cases) just realized back to the actual object upon access (where the array access is now indirect through a wrapper) but also handles the case where the value is being set through the Anyway, I could have a look at the #19286 if there is the possibility that these will end up being merged? Have a good day! |
#19286 cannot be fixed in System.Linq.Expression interpreter alone. System.Linq.Expression interpreter is built on top of reflection. The problem is that reflection does not have full support for byrefs. We would have to add new reflection APIs that provide full support for byrefs first. There is more discussion about it in the issue. In any case, high fidelity byref support in the interpreter sounds like a significant new feature to me. I do not expect it to be merged per https://github.com/dotnet/runtime/blob/main/src/libraries/System.Linq.Expressions/README.md . |
OK I believe that these have been resolved now - actually just removed what I'd added to make the code look "nicer" (more symmetrical) but that had lead to the use of |
A bug was discovered where
Expression<>.Compile(true)
would return a different result toExpression<>.Compile(false)
. The result in the case of the interpreter meant that fields of a value type embedded within a reference type could not be set, as the interpreter was setting the fields on a boxed version of the value type.The following unit test demonstrates this functionality:
This PR fixes this issue by utilizing
TypedReference
to access the fields. A special typeFieldData
was added into theInterpretedFrame
'sData
stack which is then used to determine if the slot represents a value type field access. Externally what was exposed as an object array is now wrapped, and access unwraps to the actual object upon access.The
FieldOperations
class is the only class that is required to handle the addedFieldData
type.NOTE: Tests for the System.Linq.Expressions library had been ignored in debug builds (due to speed reasons) but I have commented out that in order that they are executed. So presumably that change would be reversed before this PR is pulled into the mainline...